﻿using System.Collections.Generic;
using Grpc.Core;
using Grpc.Net.Client.Balancer;

namespace Frontend.Balancer;

public record ReportedSubchannelState(Subchannel Subchannel, ConnectivityState State);

public class ReportingChannelControlHelper : IChannelControlHelper
{
    private readonly IChannelControlHelper _controller;
    private readonly SubchannelReporter _subchannelReporter;
    private readonly List<ReportedSubchannelState> _subchannels;

    private ConnectivityState _state;

    public ReportingChannelControlHelper(
        IChannelControlHelper controller,
        SubchannelReporter subchannelReporter)
    {
        _controller = controller;
        _subchannels = new List<ReportedSubchannelState>();
        _subchannelReporter = subchannelReporter;
    }

    public Subchannel CreateSubchannel(SubchannelOptions options)
    {
        var subchannel = _controller.CreateSubchannel(options);
        subchannel.OnStateChanged(s => OnSubchannelStateChanged(subchannel, s));
        _subchannels.Add(new ReportedSubchannelState(subchannel, ConnectivityState.Idle));

        NotifySubscribers();

        return subchannel;
    }

    private void OnSubchannelStateChanged(Subchannel subchannel, SubchannelState s)
    {
        var i = _subchannels.FindIndex(s => s.Subchannel == subchannel);
        if (i >= 0)
        {
            if (s.State == ConnectivityState.Shutdown)
            {
                _subchannels.RemoveAt(i);
            }
            else
            {
                _subchannels[i] = new ReportedSubchannelState(subchannel, s.State);
            }
        }
    }

    public void UpdateState(BalancerState state)
    {
        _controller.UpdateState(state);
        _state = state.ConnectivityState;

        NotifySubscribers();
    }

    private void NotifySubscribers()
    {
        _subchannelReporter.NotifySubscribers(new SubchannelReporterResult(_state, _subchannels));
    }

    public void RefreshResolver()
    {
        _controller.RefreshResolver();
    }
}
